<script lang="ts" setup>
import type {
  AntTreeNodeDropEvent,
  TreeDataItem,
  TreeProps,
} from 'ant-design-vue/es/tree';

import { ref, watch } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import {
  DeleteOutlined,
  EditOutlined,
  EllipsisOutlined,
} from '@ant-design/icons-vue';
import { Modal } from 'ant-design-vue';

import { Apis } from '#/api';
import HighlightText from '#/components/highlight-text/index.vue';

import { arrayToTree } from '../utils';
import EditDictTypeModal, {
  type EditDictTypeModalState,
} from './edit-dict-type-modal.vue';

const props = withDefaults(
  defineProps<{
    data: any[];
    showAction?: boolean;
  }>(),
  {
    showAction: false,
    data: () => [],
  },
);

const emit = defineEmits(['refresh', 'nodeClick']);

const originData = ref<any[]>([]);
const treeData = ref<any[]>([]);

const showCode = ref(false);
watch(
  () => props.data,
  (newVal) => {
    if (!newVal || newVal.length === 0) {
      treeData.value = [];
      return;
    }
    originData.value = newVal;
    treeData.value = arrayToTree(newVal);
  },
  { immediate: true },
);

const selectedKeys = ref<string[]>([]);
const expandedKeys = ref<string[]>([]);

const [BaseEditDictTypeModal, baseEditDictTypeModalApi] = useVbenModal({
  connectedComponent: EditDictTypeModal,
});

const searchValue = ref('');

// 递归查找函数
function searchTree(node, keyword) {
  const { name = '', code = '', children = [] } = node || {};
  if (!node) return [];
  keyword = `${keyword}`;
  // 判断当前节点是否匹配关键字
  const isMatch = name.includes(keyword) || code.includes(keyword);

  // 如果有子节点，递归查找子节点是否匹配
  const filteredChildren = (children || [])
    .map((child) => searchTree(child, keyword)) // 递归查找子节点
    .filter((child) => child !== null); // 过滤掉未匹配的子节点

  // 如果当前节点匹配或有匹配的子节点，返回当前节点
  if (isMatch || filteredChildren.length > 0) {
    return {
      ...node,
      children: filteredChildren,
    };
  }

  // 如果当前节点和子节点都不匹配，返回 null
  return null;
}

watch(searchValue, (newVal) => {
  if (newVal) {
    const searchResult = searchTree(arrayToTree(originData.value)[0], newVal);
    treeData.value = searchResult ? [searchResult] : [];
  } else {
    treeData.value = arrayToTree(originData.value);
  }
});

const onDrop = (info: AntTreeNodeDropEvent) => {
  const dropKey = info.node.key;
  const dragKey = info.dragNode.key;
  const dropPos = info.node.pos!.split('-');
  const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
  const loop = (
    data: TreeProps['treeData'],
    key: number | string,
    callback: any,
  ) => {
    data!.forEach((item, index) => {
      if (item.key === key) {
        return callback(item, index, data);
      }
      if (item.children) {
        return loop(item.children, key, callback);
      }
    });
  };
  const data = [...treeData.value];

  // Find dragObject
  let dragObj: TreeDataItem;
  loop(
    data,
    dragKey,
    (item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
      arr!.splice(index, 1);
      dragObj = item;
    },
  );
  if (!info.dropToGap) {
    // Drop on the content
    loop(data, dropKey, (item: TreeDataItem) => {
      item.children = item.children || [];
      // / where to insert 示例添加到头部，可以是随意位置
      item.children.unshift(dragObj);
    });
  } else if (
    (info.node.children || []).length > 0 && // Has children
    info.node.expanded && // Is expanded
    dropPosition === 1 // On the bottom gap
  ) {
    loop(data, dropKey, (item: TreeDataItem) => {
      item.children = item.children || [];
      // where to insert 示例添加到头部，可以是随意位置
      item.children.unshift(dragObj);
    });
  } else {
    let ar: TreeProps['treeData'] = [];
    let i = 0;
    loop(
      data,
      dropKey,
      (_item: TreeDataItem, index: number, arr: TreeProps['treeData']) => {
        ar = arr;
        i = index;
      },
    );
    if (dropPosition === -1) {
      ar.splice(i, 0, dragObj);
    } else {
      ar.splice(i + 1, 0, dragObj);
    }
  }
  treeData.value = data;
};

/** 当前选中的节点 */
const selectNode = ref<any>({});
/** 节点点击 */
function handleNodeClick(treeKey: string | undefined) {
  if (treeKey === selectNode.value.code) {
    treeKey = undefined;
    selectNode.value = {};
  }
  if (treeKey !== undefined) {
    const row = originData.value.find((item) => item.code === treeKey);
    selectNode.value = row || {};
  }
  emit('nodeClick', selectNode.value);
}
/** 编辑 */
function handleEdit(id?: any) {
  const row = originData.value.find((item) => item.id === id);

  baseEditDictTypeModalApi.setData<EditDictTypeModalState>({
    isUpdate: !!id,
    record: row || {
      parentId:
        selectNode.value.parentId === '0'
          ? selectNode.value.id
          : selectNode.value.parentId,
    },
  });

  baseEditDictTypeModalApi.open();
}

/** 删除 */
function handleDelete(id: any) {
  const row = originData.value.find((item) => item.id === id);
  Modal.confirm({
    title: '确定要删除吗？',
    content: `删除后，${row?.name}将无法使用`,
    onOk: async () => {
      await Apis.system.dictType.delete({
        pathParams: { id },
      });
      emit('refresh');
    },
  });
}
/** 是否所有节点已展开 */
const isExpandAll = ref(false);

/** 展开/折叠所有节点 */
function handleExpandAll(expand: boolean) {
  treeData.value.forEach((item) => {
    if (expand && !expandedKeys.value.includes(item.key)) {
      expandedKeys.value.push(item.key);
    }
    if (!expand && expandedKeys.value.includes(item.key)) {
      expandedKeys.value = expandedKeys.value.filter((key) => key !== item.key);
    }
  });
  isExpandAll.value = expand;
}

/** 刷新 */
function handleSuccess() {
  emit('refresh');
}
</script>
<template>
  <div class="h-full overflow-auto">
    <BaseEditDictTypeModal @success="handleSuccess" />

    <div class="flex items-center justify-between">
      <span class="text-[1rem]">字典类型</span>
      <a-space v-if="props.showAction">
        <a-button type="primary" @click="handleEdit()">添加</a-button>
        <a-button @click="handleExpandAll(!isExpandAll)">
          {{ isExpandAll ? '折叠' : '展开' }}
        </a-button>
        <a-dropdown>
          <a class="ant-dropdown-link" @click.prevent>
            <EllipsisOutlined class="cursor-pointer text-lg" />
          </a>
          <template #overlay>
            <a-menu>
              <a-menu-item>
                <a href="javascript:;" @click="showCode = !showCode">
                  {{ showCode ? '隐藏编码' : '显示编码' }}
                </a>
              </a-menu-item>
            </a-menu>
          </template>
        </a-dropdown>
      </a-space>
    </div>

    <a-input
      v-model:value="searchValue"
      class="my-2"
      placeholder="输入字典类型名称/编码搜索"
    />

    <a-tree
      v-model:expanded-keys="expandedKeys"
      v-model:selected-keys="selectedKeys"
      :tree-data="treeData"
      block-node
      draggable
      selectable
      show-icon
      @drop="onDrop"
    >
      <template #title="{ key: treeKey, title, code }">
        <div class="flex" @click="handleNodeClick(code)">
          <div class="flex-1 flex-col">
            <HighlightText :content="title" :highlight-value="searchValue" />
            <div v-show="showCode" class="mt-[-4px] text-xs text-gray-400">
              <HighlightText :content="code" :highlight-value="searchValue" />
            </div>
          </div>
          <a-space>
            <EditOutlined
              class="text-primary"
              @click.stop="handleEdit(treeKey)"
            />
            <DeleteOutlined
              class="text-red-500"
              @click.stop="handleDelete(treeKey)"
            />
          </a-space>
        </div>
      </template>
    </a-tree>
  </div>
</template>

<style lang="scss" scoped></style>
